package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.heima.apis.article.IArticleClient;
import com.heima.common.aliyun.GreenImageScan;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.common.constants.WemediaConstants;
import com.heima.common.exception.CustomException;
import com.heima.common.tess4j.Tess4jClient;
import com.heima.file.service.FileStorageService;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmChannel;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmSensitive;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.model.wemedia.vo.WmNewsContentVO;
import com.heima.model.wemedia.vo.WmNewsTextImageVO;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.utils.thread.WmThreadLocalUtil;
import com.heima.wemedia.mapper.WmChannelMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmSensitiveMapper;
import com.heima.wemedia.mapper.WmUserMapper;
import com.heima.wemedia.service.WmNewsAutoScanService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author brianxia
 * @version 1.0
 * @date 2022-09-17 14:16
 */
@Service
@Slf4j
public class WmNewsAutoScanServiceImpl implements WmNewsAutoScanService {

    @Autowired
    private GreenTextScan greenTextScan;
    @Autowired
    private GreenImageScan greenImageScan;
    @Autowired
    private FileStorageService fileStorageService;
    @Autowired
    private WmNewsMapper wmNewsMapper;
    @Autowired
    private IArticleClient articleClient;
    @Autowired
    private WmUserMapper wmUserMapper;
    @Autowired
    private WmChannelMapper wmChannelMapper;
    @Autowired
    private WmSensitiveMapper wmSensitiveMapper;
    @Autowired
    private Tess4jClient tess4jClient;

    @PostConstruct
    public void init(){

        List<WmSensitive> wmSensitives = wmSensitiveMapper.
                selectList(Wrappers.<WmSensitive>lambdaQuery().select(WmSensitive::getSensitives));

        List<String> sensitives = wmSensitives.stream().map(WmSensitive::getSensitives).collect(Collectors.toList());

        //初始化敏感词库
        SensitiveWordUtil.initMap(sensitives);
    }

    //方法执行变成异步执行
    @Async
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void autoScan(WmNews wmNews) {

        System.out.println(Thread.currentThread().getName());

        //1.查询文章
        if(!Objects.equals(wmNews.getStatus(),WmNews.Status.SUBMIT.getCode())){
            return;
        }

        //1.1 文本和图片获取出来
        WmNewsTextImageVO content = getContentTextAndImage(wmNews);

        //自管理敏感词审核
        if(!handleSensitiveScan(content.getText(), wmNews)){
            return;
        }


        //2.文章文本审核 失败 2  人工 3
        if(!checkContentText(content.getText(), wmNews)){
            return;
        }

        //3.文章图片审核
        if(!checkContentImage(content.getUrls(), wmNews)){
            return;
        }

        //4.审核通过，通过远程接口调用生成文章
        ResponseResult result = saveAppArticle(wmNews);
        if(result == null || !Objects.equals(result.getCode(), AppHttpCodeEnum.SUCCESS.getCode())){
            throw new CustomException(AppHttpCodeEnum.SERVER_ERROR);
        }

        //获取文章ID
        Long data = (Long) result.getData();

        //5.成功，修改文章状态为9
        wmNews.setArticleId(data);
        updateWmNewsScanStatus(wmNews,WmNews.Status.PUBLISHED,"审核成功");

    }

    private boolean handleSensitiveScan(String text, WmNews wmNews) {


        Map<String, Integer> map = SensitiveWordUtil.matchWords(text);
        if(!map.isEmpty()){
            //包含敏感词
            updateWmNewsScanStatus(wmNews, WmNews.Status.FAIL, "图片中包含违规内容");
            return false;
        }

        return true;
    }

    //调用远程接口生成文章数据
    private ResponseResult saveAppArticle(WmNews wmNews) {

        ArticleDto dto = new ArticleDto();
        BeanUtils.copyProperties(wmNews,dto);

        //id处理
        dto.setId(wmNews.getArticleId());
        dto.setAuthorId(Long.valueOf(wmNews.getUserId()));
        //查询用户名
        WmUser wmUser = wmUserMapper.selectById(wmNews.getUserId());
        if(wmUser != null){
            dto.setAuthorName(wmUser.getName());
        }
        //频道查询
        WmChannel wmChannel = wmChannelMapper.selectById(wmNews.getChannelId());
        if(wmChannel != null){
            dto.setChannelName(wmChannel.getName());
        }
        dto.setLayout(wmNews.getType());
        dto.setFlag((byte) 0);
        dto.setCreatedTime(new Date());


        return articleClient.save(dto);
    }

    private boolean checkContentImage(List<byte[]> images, WmNews wmNews) {

        try{

            Map map = greenImageScan.imageScan(images);
            if(map != null){
                //提取map中的suggestion
                String suggestion = (String) map.get("suggestion");
                if("block".equals(suggestion)){
                    updateWmNewsScanStatus(wmNews, WmNews.Status.FAIL, "图片中包含违规内容");
                    return false;
                }else if("review".equals(suggestion)){
                    //出现异常 转人工
                    updateWmNewsScanStatus(wmNews, WmNews.Status.ADMIN_AUTH, "审核接口无法判断，转人工处理");
                    return false;
                }else if("pass".equals(suggestion)){
                    //pass
                    return true;
                }
            }

        }catch (Exception e){
            log.error("调用阿里云失败",e);
        }

        updateWmNewsScanStatus(wmNews, WmNews.Status.ADMIN_AUTH, "审核接口调用失败，转人工处理");
        return false;
    }

    /**
     * 使用阿里云审核内容中文本
     * @param text 需要审核的文本
     * @param wmNews 文章对象，方便修改数据库
     * @return true审核成功 false审核失败
     */
    public boolean checkContentText(String text,WmNews wmNews){
        try{
            Map map = greenTextScan.greeTextScan(text);
            if(map != null){
                //提取map中的suggestion
                String suggestion = (String) map.get("suggestion");
                if("block".equals(suggestion)){
                    updateWmNewsScanStatus(wmNews, WmNews.Status.FAIL, "内容中包含敏感词");
                    return false;
                }else if("review".equals(suggestion)){
                    //出现异常 转人工
                    updateWmNewsScanStatus(wmNews, WmNews.Status.ADMIN_AUTH, "审核接口无法判断，转人工处理");
                    return false;
                }else if("pass".equals(suggestion)){
                    //pass
                    return true;
                }
            }

        }catch (Exception e){
            log.error("调用阿里云失败",e);
        }

        updateWmNewsScanStatus(wmNews, WmNews.Status.ADMIN_AUTH, "审核接口调用失败，转人工处理");
        return false;
    }

    /**
     * 更新审核状态
     * @param wmNews
     * @param adminAuth
     * @param reason
     */
    private void updateWmNewsScanStatus(WmNews wmNews, WmNews.Status adminAuth, String reason) {
        wmNews.setStatus(adminAuth.getCode());
        wmNews.setReason(reason);
        wmNewsMapper.updateById(wmNews);
    }

    /**
     * 获取内容中的文本图片
     * @param wmNews
     * @return
     */
    private WmNewsTextImageVO getContentTextAndImage(WmNews wmNews) {

        Set<String> urls = new HashSet<>();
        StringBuilder sbuiler = new StringBuilder();
        String content = wmNews.getContent();
        List<WmNewsContentVO> wmNewsContentVOS = JSON.parseArray(content, WmNewsContentVO.class);
        for (WmNewsContentVO wmNewsContentVO : wmNewsContentVOS) {
            if(Objects.equals(wmNewsContentVO.getType(), WemediaConstants.WM_NEWS_TYPE_IMAGE)){
                //图片
                urls.add(wmNewsContentVO.getValue());
            }else if (Objects.equals(wmNewsContentVO.getType(), WemediaConstants.WM_NEWS_TYPE_TEXT)){
                //文本
                sbuiler.append("。" + wmNewsContentVO.getValue());
            }
        }

        //标题
        sbuiler.append("。" + wmNews.getTitle());

        //封面图片url a.jpg,b.jpg,c.jpg
        if(StringUtils.isNotBlank(wmNews.getImages())){
            String[] split = StringUtils.split(wmNews.getImages(), ",");
            urls.addAll(Arrays.asList(split));
        }

        List<String> imageUrls = new ArrayList<>(urls);
        //下载图片
        List<byte[]> images = new ArrayList<>();
        for (String url : urls) {
            byte[] bytes = fileStorageService.downLoadFile(url);
            images.add(bytes);

            try{
                ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
                BufferedImage read = ImageIO.read(inputStream);
                //使用OCR提取图片中的文本
                String text = tess4jClient.doOCR(read);
                sbuiler.append("。" + text);
            }catch (Exception e){
                log.error("读取图片失败",e);
            }

        }

        WmNewsTextImageVO wmNewsTextImageVO = new WmNewsTextImageVO();
        wmNewsTextImageVO.setText(sbuiler.toString());
        wmNewsTextImageVO.setUrls(images);

        return wmNewsTextImageVO;
    }

    public static void main(String[] args) {
        Integer[] abc = {1,2,3,4};
        List<Integer> list = Arrays.asList(abc);
        ArrayList<Integer> list2 = new ArrayList<>(list);
        list2.add(5);


    }
}
